package idplib

import (
	"fmt"
	"github.com/StackExchange/wmi"
	"golang.org/x/sys/windows/registry"
	"sort"
	"strconv"
	"strings"
)

// GetBaseBoardInfo CODE_GET_BASE_BOARD
func GetBaseBoardInfo() (data []BoardBaseInfo) {
	err := wmi.Query("SELECT * FROM Win32_BaseBoard", &data)
	if err != nil {
		return
	}
	return data
}

// GetSystemAbstractInfo CODE_GET_COMPUTER_ABSTRACT
func GetSystemAbstractInfo() (data []SystemAbstract) {
	err := wmi.Query("select * from Win32_ComputerSystem", &data)
	if err != nil {
	}
	return data
}

// GetDiskInfo CODE_DISK
func GetDiskInfo() (rd []DiskBaseInfo) {
	var data []DiskBaseInfo
	err := wmi.Query("SELECT * FROM Win32_DiskDrive", &data)
	if err != nil {
		return
	}
	for index := range data {
		data[index].SerialNumber = strings.TrimSpace(data[index].SerialNumber)
		if data[index].Size != 0 {
			rd = append(rd, data[index])
		}
	}
	return rd
}

// GetLogicDiskInfo CODE_LOGIC_DISK
func GetLogicDiskInfo() (result []LogicDiskInfoWarn) {
	var data []LogicDiskInfo
	err := wmi.Query(logic_disk_qwl, &data)
	if err != nil {
		return
	}
	for index := range data {
		if data[index].VolumeSerialNumber != "" {
			rd := LogicDiskInfoWarn{
				Caption:            data[index].Caption,
				Description:        data[index].Description,
				DeviceID:           data[index].DeviceID,
				DriveType:          data[index].DriveType,
				FileSystem:         data[index].FileSystem,
				FreeSpace:          data[index].FreeSpace,
				Size:               data[index].Size,
				SupportsDiskQuotas: data[index].SupportsDiskQuotas,
				VolumeName:         data[index].VolumeName,
				VolumeSerialNumber: data[index].VolumeSerialNumber,
				Warn:               0,
			}
			num, err := strconv.ParseFloat(data[index].Size, 64) // 第三个参数指定了结果的大小（bit数），这里为64
			if err == nil {
				if float64(data[index].FreeSpace)/num < 0.1 {
					rd.Warn = 1
				}
			}
			result = append(result, rd)
		}
	}
	return result
}

// GetMemoryInfo CODE_MEMORY
func GetMemoryInfo() []MemoryBaseInfo {
	data := make([]MemoryBaseInfo, 0)
	err := wmi.Query("SELECT * FROM Win32_PhysicalMemory", &data)
	if err != nil {
		return data
	}
	return data
}

// GetActiveNetWorkInfo CODE_NETWORK_MAC
func GetActiveNetWorkInfo() (mac NetWork, isOk bool) {
	var data []NetWork
	err := wmi.Query("SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))", &data)
	if err != nil {
		return
	}
	if len(data) == 1 {
		return data[0], true
	} else {
		return NetWork{}, false
	}
}

// GetActiveIP CODE_NETWORK_IP
func GetActiveIP() (ip NetworkConfig, isOk bool) {
	mac, ok := GetActiveNetWorkInfo()
	if ok {
		var data []NetworkConfig
		wql := "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True AND index = " + fmt.Sprint(mac.Index)
		err := wmi.Query(wql, &data)
		if err != nil {
			return
		}
		if len(data) == 1 {
			return data[0], true
		} else {
			return NetworkConfig{}, false
		}

	} else {
		return NetworkConfig{}, false
	}
}

// GetAllNetWorkInfo CODE_NETWORK
func GetAllNetWorkInfo() (wiredmac []NetworkWire, wirelessdmac []NetworkWire) {
	var data []NetWork
	var netdata []NetworkConfig
	err := wmi.Query("SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))", &data)
	if err != nil {
		return
	}
	for _, macadd := range data {
		k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\ControlSet001\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\`+fmt.Sprintf("%04d", macadd.Index), registry.QUERY_VALUE)
		defer k.Close()
		if err != nil {
			k, err = registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\`+fmt.Sprintf("%04d", macadd.Index), registry.QUERY_VALUE)
			defer k.Close()
		}
		v, _, _ := k.GetIntegerValue("Characteristics")
		vv, _, _ := k.GetIntegerValue("*MediaType")
		if v >= 4 {
			binary := strconv.FormatInt(int64(v), 2)
			sign := string(binary[len(binary)-3])
			if sign == "1" {
				wql := "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE index = " + fmt.Sprint(macadd.Index)
				err := wmi.Query(wql, &netdata)
				if err != nil {
					return
				}
				if vv == 0 {
					temdata := NetworkWire{
						DefaultIPGateway:     netdata[0].DefaultIPGateway,
						DNSServerSearchOrder: netdata[0].DNSServerSearchOrder,
						IPAddress:            netdata[0].IPAddress,
						Index:                netdata[0].Index,
						Name:                 macadd.Name,
						MACAddress:           netdata[0].MACAddress,
						Speed:                macadd.Speed,
						Wire:                 1,
					}
					wiredmac = append(wiredmac, temdata)
				} else {
					temdata := NetworkWire{
						DefaultIPGateway:     netdata[0].DefaultIPGateway,
						DNSServerSearchOrder: netdata[0].DNSServerSearchOrder,
						IPAddress:            netdata[0].IPAddress,
						Index:                netdata[0].Index,
						Name:                 macadd.Name,
						MACAddress:           netdata[0].MACAddress,
						Speed:                macadd.Speed,
						Wire:                 0,
					}
					wirelessdmac = append(wirelessdmac, temdata)
				}
			}

		}
	}
	return wiredmac, wirelessdmac
}

// GetOperatingSystem CODE_OPERATING_SYSTEM
func GetOperatingSystem() (data []OperatingSystem) {
	err := wmi.Query("select * from Win32_OperatingSystem", &data)
	if err != nil {
		return
	}
	for index := range data {
		data[index].Name = strings.Split(data[index].Name, "|")[0]
		data[index].InstallDate = strings.Split(data[index].InstallDate, ".")[0]
		data[index].LastBootUpTime = strings.Split(data[index].LastBootUpTime, ".")[0]
	}
	return data
}

// GetCpuInfo CODE_PROCESOR
func GetCpuInfo() []CpuBaseInfo {
	data := make([]CpuBaseInfo, 0)
	err := wmi.Query("SELECT * FROM Win32_Processor", &data)
	if err != nil {
		return data
	}
	return data
}

// GetProcessInfo CODE_PROCESS
func GetProcessInfo() (data []ProcessInfo) {
	err := wmi.Query("select * from Win32_Process", &data)
	if err != nil {
		return
	}
	return data
}

// GetService CODE_SERVICE
func GetService() (data []Service) {
	_ = wmi.Query("select * from Win32_Service", &data)
	return data
}

// GetStartupCommandInfo CODE_STARTUP_COMMAND
func GetStartupCommandInfo() (data []StartupCommandInfo) {
	_ = wmi.Query("select * from Win32_StartupCommand", &data)
	return data
}

// GetSoftWallInfo CODE_SOFTWARE
func GetSoftWallInfo() (data []SoftInfo) {
	var list []SoftInfo
	_ = wmi.Query("SELECT * FROM Win32_PRODUCT ", &list)
	for _, soft := range list {
		data = append(data, SoftInfo{
			IdentifyingNumber: soft.IdentifyingNumber,
			Name:              soft.Name,
			Vendor:            soft.Vendor,
			Version:           soft.Version,
			Caption:           soft.Caption,
		})
	}
	return
}

// GetServicePackInfo CODE_SERVER_PACKAGEINFO
func GetServicePackInfo() (data []ServicePack) {
	var list []PackList
	_ = wmi.Query("SELECT * FROM Win32_QuickFixEngineering", &list)
	for _, patch := range list {
		data = append(data, ServicePack{
			Source:      patch.CSName,
			Description: patch.Description,
			HotFixID:    patch.HotFixID,
			InstalledBy: patch.InstalledBy,
			InstalledOn: patch.InstalledOn,
		})
	}
	return
}

// GetUsbControllerDevice CODE_USB_CONTROLLER_DEVICE
//
//	func GetUsbControllerDevice() (data []UsbId) {
//		var tem []UsbController
//		err := wmi.Query("select * from win32_usbcontrollerdevice", &tem)
//		if err != nil {
//			return
//		}
//		var strArr []string
//		for index := range tem {
//			var item = tem[index]
//			if strings.Contains(item.Dependent, "VID") && strings.Contains(item.Dependent, "PID") {
//				var VIDPID = item.Dependent[strings.Index(item.Dependent, "VID")+4:strings.Index(item.Dependent, "VID")+8] +
//					":" + item.Dependent[strings.Index(item.Dependent, "PID")+4:strings.Index(item.Dependent, "PID")+8]
//				if !in(VIDPID, strArr) {
//					strArr = append(strArr, VIDPID)
//				}
//			}
//		}
//		for index := range strArr {
//			data = append(data, UsbId{strArr[index]})
//		}
//		return data
//	}
func in(target string, str_array []string) bool {
	sort.Strings(str_array)
	index := sort.SearchStrings(str_array, target)
	if index < len(str_array) && str_array[index] == target {
		return true
	}
	return false
}

// GetDisplayInfo CODE_DESKTOP_MONITOR
func GetDisplayInfo() (rd []displayInfoTransition) {
	var data []displayInfo
	err := wmi.Query("SELECT * FROM Win32_DesktopMonitor ", &data)
	if err != nil {
		return
	}
	for index := range data {
		if data[index].PNPDeviceID != "" && len(strings.Split(data[index].PNPDeviceID, "\\")) > 2 {
			data[index].PNPDeviceID = strings.Split(data[index].PNPDeviceID, "\\")[1]
			rd = append(rd, displayInfoTransition{Description: data[index].Description,
				Name: data[index].Name, HardwareID: data[index].PNPDeviceID})
		}
	}
	return rd
}

// GetDisplayInfoByLogicalDevice CODE_DESKTOP_BY_LOGICAL_DEVICE
func GetDisplayInfoByLogicalDevice() (rd []displayInfoTransition) {
	var data []displayInfo
	err := wmi.Query("SELECT * FROM CIM_LogicalDevice where DeviceID like 'DISPLAY%' ", &data)
	if err != nil {
		return
	}
	for index := range data {
		if data[index].PNPDeviceID != "" && len(strings.Split(data[index].PNPDeviceID, "\\")) > 2 {
			data[index].PNPDeviceID = strings.Split(data[index].PNPDeviceID, "\\")[1]
			rd = append(rd, displayInfoTransition{Description: data[index].Description,
				Name: data[index].Name, HardwareID: data[index].PNPDeviceID})
		}
	}
	return rd
}

// GetBiosInfo CODE_BIOS_CODE
func GetBiosInfo() []BiosInfo {
	var data []BiosInfo
	err := wmi.Query("SELECT * FROM Win32_BIOS ", &data)
	if err != nil {
		return data
	} else if len(strings.TrimSpace(data[0].SerialNumber)) <= 0 {
		data[0].SerialNumber = "INVALID"
	}
	return data
}
